import ComparableObj from "../core/ComparableObj";
import Obj, {equalsTo} from "../core/Obj";
import Collection from "../core/Collection";
import {hash} from "../core/Hash";

export enum IterationDirection {
  CENTRE,
  LEFT,
  RIGHT
}

export default interface Tree<E extends ComparableObj<E>> extends Obj {

  size(): number;

  capacity(): number;

  clear(): void;

  isEmpty(): boolean;

  isFull(): boolean;

  grow(capacity: number): void;

  contains(e: E): boolean;

  get(e: E): E | undefined;

  add(e: E): E | undefined;

  remove(e: E): E | undefined;

  max(): E | undefined;

  min(): E | undefined;

  collect(iterationDirection: IterationDirection, collection: Collection<E>): void;
}

export class Node<E extends ComparableObj<E>> extends Obj {
  protected left: Node<E> | undefined;
  protected right: Node<E> | undefined;

  public constructor(public key: E) {
    super();
    this.left = undefined;
    this.right = undefined;
  }

  public getLeft(): Node<E> | undefined {
    return this.left;
  }

  public setLeft(left: Node<E> | undefined): Node<E> | undefined {
    let oldValue = this.left;
    this.left = left;
    return oldValue;
  }

  public getRight(): Node<E> | undefined {
    return this.right;
  }

  public setRight(right: Node<E> | undefined): Node<E> | undefined {
    let oldValue = this.right;
    this.right = right;
    return oldValue;
  }

  public equals(b: Obj): boolean {
    if (b instanceof Node) {
      return equalsTo(this.left, b.left) && equalsTo(this.right, b.right);
    }
    return false;
  }

  public hashCode(): number {
    return hash(this.left, this.right);
  }
}
